I realise there is a benefit to not integrating with the $animate service, and having a purely class-based solution.
If you use $animate with addClass and removeClass, but interrupt the animation (say, by clicking quickly and repeatedly on the element), the animation will 'jerk' to its end/starting point, and then animate from that position, at least on Chrome. Using a pure CSS solutions avoids this issue, and always animates from the exact current point, giving a smoother effect.
An added benefit is the solution is also simpler, and you don't need a custom directive.
For example, the HTML can be as follows:
<flip class="{{side === 'front' ? 'flip-front' : 'flip-back'}}">
  <flip-front>
    Front side contents
  </flip-front>
  <flip-back>
    Rear contents
  </flip-back>
</flip>
I use custom elements, but they don't need to have any directives attached: they are just for CSS to hook into:
flip > flip-front, flip > flip-back { 
  -webkit-backface-visibility: hidden; 
  backface-visibility: hidden; 
  /* Time can be overriden */
  transition: -webkit-transform 0.5s; 
  transition: transform 0.5s;
}
/* Front visible */
flip > flip-front {
  -webkit-transform:  perspective(800px) rotateY(0); 
  transform:  perspective(800px) rotateY(0);  
}
flip > flip-back {
 -webkit-transform:  perspective(800px) rotateY(180deg); 
 transform:  perspective(800px) rotateY(180deg);   
}
/* Back visible */
flip.flip-back > flip-front {
  -webkit-transform:  perspective(800px) rotateY(-180deg); 
  transform:  perspective(800px) rotateY(-180deg);  
}
flip.flip-back > flip-back {
 -webkit-transform:  perspective(800px) rotateY(0); 
 transform:  perspective(800px) rotateY(0);   
}
This can be seen in a demo at http://plnkr.co/edit/A7IeGa1JEsZishmTDTaK?p=preview