Imagine spending an significant portion of your day migrating all your internal apps to the latest major version of an internal package, then you can imagine what we faced once a month.
We stopped doing breaking changes after a while. Instead we're effectively doing versioning at the module level. If module A could really use a fixup, we make an entirely new module A.V2, and start using that in new code. Things that don't need the new functionality can keep using the old API, which still works, and upgrade whenever we have some extra time (we never have extra time) or we really _really_ need to.
We've also adopted a policy that nothing gets added to our internal packages before they've been used in an application for a certain amount of time. Code duplication between applications is fine if we don't know exactly how the API should work, that way you have flexibility to change the code to fit a specific use case for a specific application.
If that common functionality really has to be common _straight_ away (which we surprisingly haven't hit yet) we could place it in a module A.Unstable to make certain everyone knows that it can break at any point.
In either case. It's just as important to avoid breaking changes in internal software as in everywhere else. Breaking changes are not free, except for the library authors.
I think the Go module system encourages you to avoid adding unnecessary boundaries. As someone else pointed out already, one of the problems is that you don't find out that boundaries are bad until you hit v2, and then you discover that you have this chunk of technical debt (unnecessary repo boundaries that slow down development) that you didn't know about.