Ok, never mind, found the relevant information under the Cache Revalidation and Reload Controls section of the HTTP Spec
Basically, you can serve all the different validators you want but you must be aware that in such case proxies may have a set of different validators from their own cache and from various user agents communicating with the proxy. They may choose to send one to you and that might not be the correct or the most optimal one for the end-users. However, a "best approach" has been suggested in the spec.
I suppose this should covers Expires headers as well as ETags, Cache-Control and whatnot.
Here's the relevant excerpt, in case anyone's interested:
  When an intermediate cache is forced,
  by means of a max-age=0 directive, to
  revalidate its own cache entry, and
  the client has supplied its own
  validator in the request, the supplied
  validator might differ from the
  validator currently stored with the
  cache entry. In this case, the cache
  MAY use either validator in making its
  own request without affecting semantic
  transparency. However, the choice of
  validator might affect performance.
  The best approach is for the
  intermediate cache to use its own
  validator when making its request. If
  the server replies with 304 (Not
  Modified), then the cache can return
  its now validated copy to the client
  with a 200 (OK) response. If the
  server replies with a new entity and
  cache validator, however, the
  intermediate cache can compare the
  returned validator with the one
  provided in the client's request,
  using the strong comparison function.
  If the client's validator is equal to
  the origin server's, then the
  intermediate cache simply returns 304
  (Not Modified). Otherwise, it returns
  the new entity with a 200 (OK)
  response. If a request includes the
  no-cache directive, it SHOULD NOT
  include min-fresh, max-stale, or
  max-age.