Here are a few techniques to restrict the potential for privilege escalation:
Chroot daemons when possible - On Unix-based systems applications can be run "chrooted". This restricts the file system space visible to the application by changing the apparent root directory for that application. This can greatly restrict the potential for abuse.
Run services as unprivileged accounts - This is one of the most basic, but is often overlooked. On Windows, the service you design does not need to run as Local System simply because it is a service. Learn what rights the service actually needs and use an otherwise restricted account that has been granted those rights.
Use bounds checkers and stress tests when debugging - Many privilege escalations take place when applications crash. Some applications will simply need more privileges in order to do anything useful, so we should test them thoroughly and debug them as best we can to limit the potential for buffer overruns and crashes to provide a vector for privilege escalation.
Require multi-factor authentication & authorization - For large multi-user systems, with disparate data repositories and applications, a multitude of user sessions are running concurrently. Consider in your architecture requiring more than simply a single authentication step to access data. Escalating privilege of one step in the process will buy them nothing if additional validation is required.