diff --git a/domain.admin.inc b/domain.admin.inc
index 47dda4d..a91e96a 100644
--- a/domain.admin.inc
+++ b/domain.admin.inc
@@ -342,6 +342,29 @@ function domain_configure_form($form, &$form_state, $user_submitted = FALSE) {
       Enter one path per line.  See the README for more details.')
   );
 
+  $form['domain_classes'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Domain-specific CSS classes'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE
+  );
+  // Get the available tokens.
+  $prefixes = array('current-domain', 'default-domain');
+  module_load_include('inc', 'domain', 'domain.tokens');
+  $info = domain_token_info();
+  foreach($prefixes as $prefix) {
+    foreach($info['tokens']['domain'] as $token => $data) {
+      $tokens[] = t('!token : !description', array('!token' => "[$prefix:$token]", '!description' => $data['description']));
+    }
+  }
+  $form['domain_classes']['domain_classes'] = array(
+    '#type' => 'textarea',
+    '#rows' => 5,
+    '#cols' => 40,
+    '#default_value' => variable_get('domain_classes', 'domain-[current-domain:machine_name]'),
+    '#description' => t('Add the following classes to the <em>body</em> tag of every page. Enter one class per line. The following token replacements are allowed: !tokens', array('!tokens' => theme('item_list', array('items' => $tokens)))),
+  );
+
   // Allow submodules to add elements to the form.
   $modules = module_implements('domain_form');
   if (!empty($modules)) {
diff --git a/domain.module b/domain.module
index ba63a93..c740105 100644
--- a/domain.module
+++ b/domain.module
@@ -1117,7 +1117,13 @@ function domain_lookup($domain_id = NULL, $subdomain = NULL, $reset = FALSE) {
 function domain_default($reset = FALSE, $alter = TRUE) {
   $default = &drupal_static(__FUNCTION__);
   if (empty($default) || $reset) {
-    $default = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default FROM {domain} WHERE is_default = 1")->fetchAssoc();
+    // Temporary hack for update to 7.x.3.
+    if (db_table_exists('domain_export')) {
+      $default = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default, machine_name FROM {domain} WHERE is_default = 1")->fetchAssoc();
+    }
+    else {
+      $default = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default FROM {domain} WHERE is_default = 1")->fetchAssoc();
+    }
     // Let submodules overwrite the defaults, if they wish.
     if (empty($default)) {
       $default = array(
@@ -1126,7 +1132,8 @@ function domain_default($reset = FALSE, $alter = TRUE) {
         'sitename' => variable_get('site_name', 'Drupal'),
         'scheme' => empty($_SERVER['HTTPS']) ? 'http' : 'https',
         'valid' => 1,
-        'is_default' => 1
+        'is_default' => 1,
+        'machine_name' => domain_machine_name($default['subdomain']),
       );
     }
     if ($alter) {
@@ -3453,3 +3460,33 @@ function domain_batch_actions() {
   drupal_alter('domain_batch', $batch);
   return $batch;
 }
+
+/**
+ * Implements hook_preprocess_page().
+ */
+function domain_preprocess_html(&$variables) {
+  $classes = domain_page_classes();
+  foreach ($classes as $class) {
+    $variables['classes_array'][] = $class;
+  }
+}
+
+/**
+ * Determine the page classes to apply to the current domain.
+ *
+ * @return
+ *  An array of domain-specific HTML-safe class names.
+ */
+function domain_page_classes() {
+  $classes = array();
+  $settings = variable_get('domain_classes', 'domain-[current-domain:machine_name]');
+  if (!empty($settings)) {
+    $vars = check_plain(token_replace($settings));
+    $vars = preg_replace('/(\r\n|\n)/', "\r\n", $vars);
+    $vars = explode("\r\n", token_replace($vars));
+    foreach($vars as $var) {
+      $classes[] = drupal_clean_css_identifier(trim($var));
+    }
+  }
+  return $classes;
+}
diff --git a/domain.tokens.inc b/domain.tokens.inc
index 1eb4ef8..876dac2 100644
--- a/domain.tokens.inc
+++ b/domain.tokens.inc
@@ -31,6 +31,10 @@ function domain_token_info() {
     'name' => t('Domain id'),
     'description' => t('The domain ID.'),
   );
+  $info['tokens']['domain']['machine_name'] = array(
+    'name' => t('Domain machine name'),
+    'description' => t('The domain machine identifier.'),
+  );
   $info['tokens']['domain']['name'] = array(
     'name' => t('Domain name'),
     'description' => t('The domain name.'),
@@ -62,6 +66,9 @@ function domain_tokens($type, $tokens, array $data = array(), array $options = a
         case 'id':
           $replacements[$original] = $domain['domain_id'];
           break;
+        case 'machine_name':
+          $replacements[$original] = $domain['machine_name'];
+          break;
         case 'name':
           $replacements[$original] = $sanitize ? check_plain($domain['sitename']) : $domain['sitename'];
           break;
diff --git a/tests/domain.test b/tests/domain.test
index 3028e1d..cb8b209 100644
--- a/tests/domain.test
+++ b/tests/domain.test
@@ -596,7 +596,7 @@ class DomainCacheTest extends DomainTestCase {
   public static function getInfo() {
     return array(
       'name' => 'Domain caching tests',
-      'description' => 'Tests for proper page caching.',
+      'description' => 'Tests for proper page caching and markup.',
       'group' => 'Domain Access',
     );
   }
@@ -616,6 +616,11 @@ class DomainCacheTest extends DomainTestCase {
     // Fill the cache.
     $this->drupalGet('');
 
+    // Check the output for our body classes.
+    $domain_classes = domain_page_classes();
+    $this->assertRaw('domain-', t('Domain text found in body classes.'));
+    $this->assertRaw($domain_classes[0], t('Domain-specific body class rendered correctly: !class.', array('!class' => $domain_classes[0])));
+
     $this->drupalHead('');
     $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Page was cached on primary domain.'));
     $etag = $this->drupalGetHeader('ETag');
@@ -651,6 +656,15 @@ class DomainCacheTest extends DomainTestCase {
     // Fill the cache.
     $this->drupalGet($domains['one']['path'], $options);
 
+    // Check the output for our body classes. 
+    // Note that we set the domain to get the right variables.
+    domain_set_domain($domains['one']['domain_id'], TRUE);
+    $domain_classes2 = domain_page_classes();
+    domain_reset_domain(TRUE);
+    $this->assertRaw('domain-', t('Domain text found in body classes.'));
+    $this->assertTrue($domain_classes[0] != $domain_classes2[0], t('Body class is different for secondary domain.'));
+    $this->assertRaw($domain_classes2[0], t('Domain-specific body class rendered correctly: !class.', array('!class' => $domain_classes2[0])));
+
     $this->drupalHead($domains['one']['path'], $options);
     $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Page was cached on %domain.', array('%domain' => $domains['one']['subdomain'])));
     $etag = $this->drupalGetHeader('ETag');
