You can have multiple IPv6 addresses on your interface, so you can have both the ULA address for internal use as well as the global address - no need for NAT
However, the priority order on your OS for address selection, even when it comes to stuff like choosing which DNS results to use is IPv6 global address > IPv4 > ULAs. So on a dual stack network, ULAs with not be used unless the only address is a ULA.
And even if you run your internal services with only an AAAA record pointing to the ULA, the client's source address will likely be the global address of the client device unless you tweak the tables on each client, which then means you'll need to have your global address in all your firewall rules to access the internal services on ULAs, which then means you're not saved from having your ISP-provided global address in your configuration, which is what you were trying to avoid by using ULAs.
The problems this caused/s seems to have been an unintended / unforeseen consequence that was more exposed as people gained experience. There's a draft being worked on to officially change the priority:
> The behavior of ULA addressing as defined by [RFC6724] is preferred below legacy IPv4 addressing, thus rendering ULA IPv6 deployment functionally unusable in IPv4 / IPv6 dual-stacked environments. The lack of a consistent and supportable way to manipulate this behavior, across all platforms and at scale is counter to the operational behavior of GUA IPv6 addressing on nearly all modern operating systems that leverage a preference model based on [RFC6724].
Leaving aside that the draft is badly worded (there are long descriptions of the problem, but no short paragraph saying what must be changed), the long time until this is deployed if ever, the new order will still leave ULA below IPv6 global addresses - which means it doesn't solve stock_toaster's problem at all.