So by making respawned jobs fail by removing the "failed = FALSE" line here (http://bazaar.launchpad.net/~canonical-scott/upstart/trunk/view/head:/init/job_process.c#L1086), I was able to use the following line to get the desired effect:
stop on stopping bar RESULT=ok or stopping bar PROCESS=respawn
This will stop foo when bar is stopped normally (stop, stop on, or normal exit) and it will also stop foo when bar hits the respawn limit.
Going one step further, I added a check here (http://bazaar.launchpad.net/~canonical-scott/upstart/trunk/view/head:/init/job.c#L853) for respawn class jobs which had not hit the respawn limit, and set RESULT to "respawn" instead. This allows me to write:
stop on stopping bar RESULT!=respawn
This is a little cleaner and makes more sense to me, since the job neither technically failed or exited successfully. RESULT should be neither of 'ok' or 'failed' in this case. This also provides EXIT_SIGNAL or EXIT_STATUS for respawned jobs, which is another nice to have. Only when the respawn limit is hit will RESULT be 'failed', only when bar is stopped normally (stop, stop on, or normal exit) will RESULT be 'ok', and only when bar is respawning due to an abnormal exit will RESULT be 'respawn'.