GIT hooks could work, but the trouble is that they're not automatically installed when the developers pulls a workspace. Which means they might end up being installed/used correctly or not. Unreliable.
CI scripts could work as well, but the're reactive, simply indicating that something went wrong, in most cases humans still need to identify the culprit (which might be caused by an improper DTO subtree or by something else) and fix the problem.
If you want your developers to properly pull their subtrees - offer them a scripted wrapper to do so - put the effort into that script so that it is simple to use and robust/working well such that the developer's workflow is effectively simplified. If you manage to do this (most of) the developers will see the benefit and they will use it.
For the push side - you need to take into account that mistakes in push will happen (even with the above-mentioned script, if it's not used by all developers, for example). Everyone makes mistakes.
Personally I favour preventing developers from directly pushing their changes into the integration branch and thus blocking possible mistakes from affecting the integration branch.
Instead I'd have all candidate changes (i.e. either pushed in separate branches or just as diffs) funnelled through a mandatory centralized pre-commit verification system. Automated, of course, with the proper git subtrees management made reliable through that automation. The changes would only be committed/merged into the integration branch automatically by this system, if they meet the quality checks.
This approach is applicable to any potential regression-causing mistakes, not just improper DTO subtrees. An example of such approach would be the gerrit-based development on OpenStack.
git submodule update, people will probably find them hard to work with.