Were I work we have several internal libraries. When we crossed the point were one library was used in more than 3 services, we stopped doing breaking changes because it was simply to time consuming to upgrade to the next major version of the package.
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.