diff --git a/commons_groups.features.field_base.inc b/commons_groups.features.field_base.inc
index cd8b2c0..d3b99f5 100644
--- a/commons_groups.features.field_base.inc
+++ b/commons_groups.features.field_base.inc
@@ -10,6 +10,121 @@
 function commons_groups_field_default_field_bases() {
   $field_bases = array();
 
+  if (module_exists('og_access')) {
+    // Exported field_base: 'group_access'
+    $field_bases['group_access'] = array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'group_access',
+      'foreign keys' => array(),
+      'indexes' => array(
+        'value' => array(
+          0 => 'value',
+        ),
+      ),
+      'locked' => '0',
+      'module' => 'list',
+      'no_ui' => TRUE,
+      'settings' => array(
+        'allowed_values' => array(
+          0 => 'Public - accessible to all site users',
+          1 => 'Private - accessible only to group members',
+        ),
+        'allowed_values_function' => '',
+      ),
+      'translatable' => '0',
+      'type' => 'list_boolean',
+    );
+
+    // Exported field_base: 'group_content_access'
+    $field_bases['group_content_access'] = array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'group_content_access',
+      'foreign keys' => array(),
+      'indexes' => array(
+        'value' => array(
+          0 => 'value',
+        ),
+      ),
+      'locked' => '0',
+      'module' => 'list',
+      'no_ui' => TRUE,
+      'settings' => array(
+        'allowed_values' => array(
+          0 => 'Use group defaults',
+          1 => 'Public - accessible to all site users',
+          2 => 'Private - accessible only to group members',
+        ),
+        'allowed_values_function' => '',
+      ),
+      'translatable' => '0',
+      'type' => 'list_integer',
+    );
+  }
+
+  // Exported field_base: 'field_og_access_default_value'
+  $field_bases['field_og_access_default_value'] = array(
+    'active' => '1',
+    'cardinality' => '1',
+    'deleted' => '0',
+    'entity_types' => array(),
+    'field_name' => 'field_og_access_default_value',
+    'foreign keys' => array(),
+    'indexes' => array(
+      'value' => array(
+        0 => 'value',
+      ),
+    ),
+    'locked' => '0',
+    'module' => 'list',
+    'settings' => array(
+      'allowed_values' => array(
+        0 => '',
+        1 => '',
+      ),
+      'allowed_values_function' => '',
+    ),
+    'translatable' => '0',
+    'type' => 'list_boolean',
+  );
+
+  // Exported field_base: 'field_og_subscribe_settings'
+  $field_bases['field_og_subscribe_settings'] = array(
+    'active' => '1',
+    'cardinality' => '1',
+    'deleted' => '0',
+    'entity_types' => array(),
+    'field_name' => 'field_og_subscribe_settings',
+    'foreign keys' => array(),
+    'indexes' => array(
+      'value' => array(
+        0 => 'value',
+      ),
+    ),
+    'locked' => '0',
+    'module' => 'list',
+    'settings' => array(
+      'allowed_values' => array(
+        'anyone' => 'Anyone can join',
+        'approval' => 'Joining requires admin approval',
+        'invitation' => 'Joining requires an invitation',
+      ),
+      'allowed_values_function' => '',
+    ),
+    'translatable' => '0',
+    'type' => 'list_text',
+  );
+
+  // Alter the "approval" description when og_access is on.
+  if (module_exists('og_access')) {
+    $field_bases['field_og_subscribe_settings']['settings']['allowed_values']['invitation'] = 'Joining requires an invitation. The group and content is hidden from non-members.';
+  }
+
   // Exported field_base: 'group_group'
   $field_bases['group_group'] = array(
     'active' => '1',
@@ -60,7 +175,7 @@ function commons_groups_field_default_field_bases() {
     'locked' => '0',
     'module' => 'entityreference',
     'settings' => array(
-      'handler' => 'og',
+      'handler' => 'og_commons',
       'handler_settings' => array(
         'behaviors' => array(
           'og_behavior' => array(
@@ -137,7 +252,7 @@ function commons_groups_field_default_field_bases() {
     'locked' => '0',
     'module' => 'entityreference',
     'settings' => array(
-      'handler' => 'og',
+      'handler' => 'og_commons',
       'handler_settings' => array(
         'behaviors' => array(
           'og_behavior' => array(
@@ -186,5 +301,31 @@ function commons_groups_field_default_field_bases() {
     'type' => 'image',
   );
 
+  // Exported field_base: 'og_roles_permissions'
+  $field_bases['og_roles_permissions'] = array(
+    'active' => '1',
+    'cardinality' => '1',
+    'deleted' => '0',
+    'entity_types' => array(),
+    'field_name' => 'og_roles_permissions',
+    'foreign keys' => array(),
+    'indexes' => array(
+      'value' => array(
+        0 => 'value',
+      ),
+    ),
+    'locked' => '0',
+    'module' => 'list',
+    'settings' => array(
+      'allowed_values' => array(
+        0 => 'Use default roles and permissions',
+        1 => 'Override default roles and permissions',
+      ),
+      'allowed_values_function' => '',
+    ),
+    'translatable' => '0',
+    'type' => 'list_boolean',
+  );
+
   return $field_bases;
 }
diff --git a/commons_groups.features.field_instance.inc b/commons_groups.features.field_instance.inc
index 653dfdf..36dda8c 100644
--- a/commons_groups.features.field_instance.inc
+++ b/commons_groups.features.field_instance.inc
@@ -61,6 +61,59 @@ function commons_groups_field_default_field_instances() {
     ),
   );
 
+  if (module_exists('og_access')) {
+    // Exported field_instance: 'node-group-group_access'
+    $field_instances['node-group-group_access'] = array(
+      'bundle' => 'group',
+      'default_value' => array(
+        0 => array(
+          'value' => 0,
+        ),
+      ),
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'list',
+          'settings' => array(),
+          'type' => 'list_default',
+          'weight' => 4,
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'group_access',
+      'label' => 'Group visibility',
+      'required' => TRUE,
+      'settings' => array(
+        'user_register_form' => FALSE,
+      ),
+      'view modes' => array(
+        'full' => array(
+          'label' => 'above',
+          'type' => 'options_onoff',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'type' => 'options_onoff',
+        ),
+      ),
+      'widget' => array(
+        'module' => 'options',
+        'settings' => array(),
+        'type' => 'options_buttons',
+        'weight' => 41,
+      ),
+      'widget_type' => 'options_select',
+    );
+  }
+
    // Exported field_instance: 'node-group-group_group'
   $field_instances['node-group-group_group'] = array(
     'bundle' => 'group',
@@ -190,14 +243,155 @@ function commons_groups_field_default_field_instances() {
     ),
   );
 
+  // Exported field_instance: 'node-group-field_og_subscribe_settings'
+  $field_instances['node-group-field_og_subscribe_settings'] = array(
+    'bundle' => 'group',
+    'default_value' => array(
+      0 => array(
+        'value' => 'anyone',
+      ),
+    ),
+    'deleted' => '0',
+    'description' => '',
+    'display' => array(
+      'default' => array(
+        'label' => 'above',
+        'module' => 'list',
+        'settings' => array(),
+        'type' => 'list_default',
+        'weight' => 4,
+      ),
+      'teaser' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+    ),
+    'entity_type' => 'node',
+    'field_name' => 'field_og_subscribe_settings',
+    'label' => 'Privacy settings',
+    'required' => 1,
+    'settings' => array(
+      'user_register_form' => FALSE,
+    ),
+    'widget' => array(
+      'active' => 1,
+      'module' => 'options',
+      'settings' => array(),
+      'type' => 'options_buttons',
+      'weight' => '41',
+    ),
+  );
+
+  // Exported field_instance: 'node-group-field_og_access_default_value'
+  $field_instances['node-group-field_og_access_default_value'] = array(
+    'bundle' => 'group',
+    'default_value' => array(
+      0 => array(
+        'value' => 0,
+      ),
+    ),
+    'deleted' => '0',
+    'description' => '',
+    'display' => array(
+      'default' => array(
+        'label' => 'above',
+        'module' => 'list',
+        'settings' => array(),
+        'type' => 'list_default',
+        'weight' => 5,
+      ),
+      'teaser' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+    ),
+    'entity_type' => 'node',
+    'field_name' => 'field_og_access_default_value',
+    'label' => 'Hide contributed content from non-members',
+    'required' => 0,
+    'settings' => array(
+      'user_register_form' => FALSE,
+    ),
+    'widget' => array(
+      'active' => 1,
+      'module' => 'options',
+      'settings' => array(
+        'display_label' => 1,
+      ),
+      'type' => 'options_onoff',
+      'weight' => '42',
+    ),
+  );
+
+  // Exported field_instance: 'node-group-og_roles_permissions'
+  $field_instances['node-group-og_roles_permissions'] = array(
+    'bundle' => 'group',
+    'default_value' => array(
+      0 => array(
+        'value' => 1,
+      ),
+    ),
+    'deleted' => '0',
+    'description' => '',
+    'display' => array(
+      'default' => array(
+        'label' => 'above',
+        'module' => 'list',
+        'settings' => array(),
+        'type' => 'list_default',
+        'weight' => 1,
+      ),
+      'teaser' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+    ),
+    'entity_type' => 'node',
+    'field_name' => 'og_roles_permissions',
+    'label' => 'Group roles and permissions',
+    'required' => TRUE,
+    'settings' => array(
+      'user_register_form' => FALSE,
+    ),
+    'view modes' => array(
+      'full' => array(
+        'custom settings' => FALSE,
+        'label' => 'Full',
+        'type' => 'list_default',
+      ),
+      'teaser' => array(
+        'custom settings' => FALSE,
+        'label' => 'Teaser',
+        'type' => 'list_default',
+      ),
+    ),
+    'widget' => array(
+      'module' => 'options',
+      'settings' => array(),
+      'type' => 'options_select',
+      'weight' => 1,
+    ),
+  );
+
   // Translatables
   // Included for use with string extractors like potx.
   t('Determine if this is an OG group.');
   t('Group');
   t('Group membership');
+  t('Group visibility');
+  t('Group content visibility');
+  t('Group roles and permissions');
   t('Request message');
   t('This is the text a user may send to the group administrators.');
   t('Group Logo');
+  t('Hide contributed content from non-members');
+  t('Privacy settings');
   return $field_instances;
 }
 
@@ -271,6 +465,59 @@ function commons_groups_field_definition(&$field_instances, $entity_type, $bundl
     ),
   );
 
+  if (module_exists('og_access')) {
+    // Exported field_instance: '[entity]-[bundle]-group_content_access'
+    $field_instances["$entity_type-$bundle-group_content_access"] = array(
+      'bundle' => $bundle,
+      'default_value' => array(
+        0 => array(
+          'value' => 0,
+        ),
+      ),
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'list',
+          'settings' => array(),
+          'type' => 'list_default',
+          'weight' => 13,
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => $entity_type,
+      'field_name' => 'group_content_access',
+      'label' => 'Group content visibility',
+      'required' => TRUE,
+      'settings' => array(
+        'user_register_form' => FALSE,
+      ),
+      'view modes' => array(
+        'full' => array(
+          'label' => 'above',
+          'type' => 'list_default',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'type' => 'list_default',
+        ),
+      ),
+      'widget' => array(
+        'module' => 'options',
+        'settings' => array(),
+        'type' => 'options_select',
+        'weight' => 16,
+      ),
+      'widget_type' => 'options_select',
+    );
+  }
+
   // Exported field_instance: 'node-group-field_group_logo'
   $field_instances['node-group-field_group_logo'] = array(
     'bundle' => 'group',
diff --git a/commons_groups.info b/commons_groups.info
index 9e1ea47..93ed60b 100644
--- a/commons_groups.info
+++ b/commons_groups.info
@@ -21,7 +21,10 @@ dependencies[] = views_load_more
 features[ctools][] = strongarm:strongarm:1
 features[ctools][] = views:views_default:3.0
 features[features_api][] = api:1
+features[field_base][] = group_access
+features[field_base][] = group_content_access
 features[field_base][] = group_group
+features[field_base][] = og_roles_permissions
 features[field_base][] = og_group_ref
 features[field_base][] = og_membership_request
 features[field_base][] = og_user_group_ref
@@ -58,4 +61,6 @@ features[views_view][] = commons_group_moderation
 features[views_view][] = commons_groups_contributors
 features[views_view][] = commons_groups_directory
 features[views_view][] = commons_groups_recent_content
-features[views_view][] = commons_groups_user_groups
\ No newline at end of file
+features[views_view][] = commons_groups_user_groups
+features_exclude[field][node-group-group_group] = node-group-group_group
+features_exclude[field][node-group-group_access] = node-group-group_access
diff --git a/commons_groups.install b/commons_groups.install
index 23b8375..1f74383 100644
--- a/commons_groups.install
+++ b/commons_groups.install
@@ -62,7 +62,7 @@ function commons_groups_update_3105() {
  * (http://drupal.org/node/1821808).
  */
 function commons_groups_update_3106() {
-    $revert = array(
+  $revert = array(
       'commons_groups' => array('views_view'),
   );
   features_revert($revert);
@@ -92,4 +92,16 @@ function commons_groups_update_3107() {
     }
   }
   return array();
+}
+
+/**
+ * Update the og_group_ref and group privacy fields per
+ * http://drupal.org/node/1961296.
+ */
+function commons_groups_update_3108() {
+  $revert = array(
+      'commons_groups' => array('field_base', 'field_instance'),
+  );
+  features_revert($revert);
+  return array();
 }
\ No newline at end of file
diff --git a/commons_groups.module b/commons_groups.module
index 0802a8e..b594250 100644
--- a/commons_groups.module
+++ b/commons_groups.module
@@ -6,6 +6,25 @@
 
 include_once 'commons_groups.features.inc';
 
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function commons_groups_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference') {
+    return "plugins/entityreference/$plugin";
+  }
+}
+
+/**
+ * Implements hook_modules_enabled().
+ *
+ * Make sure the og access fields exist when og_access is enabled.
+ */
+function commons_groups_modules_enabled($modules) {
+  if (in_array('og_access', $modules)) {
+    features_revert(array('commons_groups' => array('field_base', 'field_instance')));
+  }
+}
 
 /**
  * Implements hook_entity_view().
@@ -24,6 +43,111 @@ function commons_groups_entity_view($entity, $type, $view_mode, $langcode) {
     drupal_set_breadcrumb($breadcrumb);
   }
 }
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Alter the privacy settings fields.
+ */
+function commons_groups_form_group_node_form_alter(&$form, &$form_state) {
+  // Wrap the privacy fields with a fieldset.
+  $form['privacy_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Privacy settings'),
+    '#weight' => 20,
+  );
+  $form['privacy_settings']['field_og_subscribe_settings'] = $form['field_og_subscribe_settings'];
+  unset($form['field_og_subscribe_settings']);
+
+  // Hide the settings label.
+  $form['privacy_settings']['field_og_subscribe_settings'][LANGUAGE_NONE]['#title'] = '';
+  $form['privacy_settings']['field_og_subscribe_settings'][LANGUAGE_NONE]['#required'] = FALSE;
+
+  if (module_exists('og_access')) {
+    $form['privacy_settings']['field_og_access_default_value'] = $form['field_og_access_default_value'];
+    unset($form['field_og_access_default_value']);
+
+    // Display the private content checkbox only when "Joining requires approval"
+    // is selected.
+    $form['privacy_settings']['field_og_access_default_value']['#states'] = array(
+      'visible' => array(
+        ':input[name="field_og_subscribe_settings[' . LANGUAGE_NONE . ']"]' => array('value' => 'approval'),
+      ),
+    );
+
+    $form['#after_build'] = array('commons_groups_form_group_node_after_build');
+  }
+
+  $form['#attached']['css'] = array(
+    drupal_get_path('module', 'commons_groups') . '/css/commons_groups.css',
+  );
+}
+
+/**
+ * After build callback for the group node form.
+ *
+ * Display the private content checkbox inside the privacy settings field.
+ */
+function commons_groups_form_group_node_after_build($form, $form_state) {
+  $form['privacy_settings']['field_og_subscribe_settings'][LANGUAGE_NONE]['approval']['#suffix'] = render($form['privacy_settings']['field_og_access_default_value']);
+
+  return $form;
+}
+
+/**
+ * Implements hook_og_role_change_permissions().
+ *
+ * Update the subscription settings field on a group when the relevant
+ * permissions are changed.
+ */
+function commons_groups_og_role_change_permissions($role) {
+  if (!$role->gid || $role->name != OG_ANONYMOUS_ROLE) {
+    return;
+  }
+
+  // Get all non members permissions.
+  $permissions = og_role_permissions(array($role->rid => $role->name));
+  if (!empty($permissions[$role->rid])) {
+    _commons_groups_update_group_permissions($role, $permissions[$role->rid]);
+  }
+}
+
+/**
+ * Update the group permission field.
+ *
+ * @param $role
+ *   The OG role object of which the permissions are being changed.
+ * @param $permissions
+ *   The anonymous user permissions of the group.
+ */
+function _commons_groups_update_group_permissions($role, $permissions) {
+  $updated_roles = &drupal_static(__FUNCTION__);
+  if (!empty($updated_roles[$role->rid])) {
+    // Avoid updating a group subscription twice on the same request.
+    return;
+  }
+
+  if (!empty($permissions['subscribe without approval'])) {
+    $subscribe_type = 'anyone';
+  }
+  elseif (!empty($permissions['subscribe'])) {
+    $subscribe_type = 'approval';
+  }
+  else {
+    $subscribe_type = 'invitation';
+  }
+
+  $wrapper = entity_metadata_wrapper($role->group_type, $role->gid);
+  if ($wrapper->field_og_subscribe_settings->value() != $subscribe_type) {
+    // Mark that the group's permissions were already handled on this request,
+    // to avoid saving the group entity more than once.
+    $updated_roles[$role->rid] = TRUE;
+
+    $wrapper->field_og_subscribe_settings->set($subscribe_type);
+    $wrapper->save();
+  }
+}
+
 /**
  * Implements hook_menu_alter().
  */
@@ -60,7 +184,6 @@ function commons_groups_block_view() {
 
 /**
  * Implements hook_features_pipe_alter().
- *
  */
 function commons_groups_features_pipe_alter(&$pipe, $data, $export) {
   // Prevent Commons Groups related fields from being piped in features
@@ -217,6 +340,11 @@ function commons_groups_system_info_alter(&$info, $file, $type) {
       foreach ($group_content_entity_types as $entity_type => $bundles) {
         foreach(array_keys($bundles) as $bundle) {
           $info['features']['field_instance'][] = "$entity_type-$bundle-og_group_ref";
+          $info['features']['field_instance'][] = "$entity_type-$bundle-field_og_subscribe_settings";
+          if (module_exists('og_access')) {
+            $info['features']['field_instance'][] = "$entity_type-$bundle-field_og_access_default_value";
+            $info['features']['field_instance'][] = "$entity_type-$bundle-group-group_access";
+          }
         }
       }
     }
@@ -236,34 +364,39 @@ function commons_groups_default_message_type_alter(&$defaults) {
 
 
 /**
-* Implements hook_og_user_access_alter().
-*/
-function commons_groups_og_user_access_alter(&$temp_perm, $context) {
-  // Grant access to non-group members to be able to post into groups
-  // where the group node is public and content is public within the group.
-  $commons_groups_entity_types = commons_groups_get_group_content_entity_types();
-  $group_content_restricted = (bool) (isset($context['group']->group_content_access[LANGUAGE_NONE][0]['value']) && $context['group']->group_content_access[LANGUAGE_NONE][0]['value'] == 2);
-  // @TODO: Consider using a static here.
-  $user_is_member = (bool)og_is_member('node', $context['group']->nid, 'user', $context['account']);
-  foreach ($commons_groups_entity_types['node'] as $type => $options) {
-    // We do a literal user_access() check on the create permission here
-    // because we can't call node_access() OR og_user_access without causing recursion.
-    // The code flow is:
-    // node_access()>og_node_access()=>og_user_access_entity=>og_user_access=>
-    // og_user_access_alter()=>commons_groups_og_user_access_alter().
-    // See also: http://drupal.org/node/1910874.
-
-    // In most cases users who don't have access to post content should already be false. But just in case they aren't, we'll set the permission here.
-    if ($context['string'] == "create $type content" && !user_access("create $type content", $context['account'])) {
-      $temp_perm["create $type content"] = FALSE;
-      return;
-    }
+ * Implements hook_og_user_access_alter().
+ *
+ * Deny create permissions from non-members on "non-public" groups (i.e. groups
+ * that don't allow joining without approval).
+ */
+function commons_groups_og_user_access_alter(&$perm, $context) {
+  $account = $context['account'];
+  $cache = &drupal_static(__FUNCTION__, array());
+  if (!empty($cache[$account->uid])) {
+    // We already changed the permissions.
+    return;
+  }
 
-    // If a group is not restricted, or the user is a member, and the user can create content of a certain type, let them post temporarily
-    if ($context['string'] == "create $type content" && (!$group_content_restricted || $user_is_member) && user_access("create $type content", $context['account'])) {
-      $temp_perm["create $type content"] = TRUE;
-      return;
-    }
+  $cache[$account->uid] = TRUE;
+  $group_type = $context['group_type'];
+  $group = $context['group'];
+
+  if ($group_type != 'node') {
+    return;
+  }
+
+  if (og_is_member($group_type, $group->nid, 'user', $account)) {
+    // The user is a group member, so comply to the OG permissions.
+    return;
+  }
+
+  $wrapper = entity_metadata_wrapper($group_type, $group);
+  $access_create = $wrapper->field_og_subscribe_settings->value() == 'anyone';
+
+  // Make sure user can view group (i.e. it's not private).
+  $commons_groups_entity_types = commons_groups_get_group_content_entity_types();
+  foreach (array_keys($commons_groups_entity_types['node']) as $type) {
+    $perm["create $type content"] = $access_create;
   }
 }
 
@@ -429,7 +562,7 @@ function commons_groups_entityreference_default_value($entity_type, $entity, $fi
     $target = entity_load_single($target_type, $target_id);
     if (entity_access('view', $target_type, $target)
       && og_is_group_type($target_type, $target->type)
-      && (og_user_access($target_type, $target_id, "create $entity->type content") || og_user_access($target_type, $id, "update any $entity->type content"))) {
+      && (og_user_access($target_type, $target_id, "create $entity->type content") || og_user_access($target_type, $target_id, "update any $entity->type content"))) {
         $items[] = array('target_id' => $target_id);
     }
   }
@@ -456,19 +589,120 @@ function commons_groups_default_rules_configuration_alter(&$configs) {
 }
 
 /**
-* Implements hook_node_update().
-*/
+ * Implements hook_node_presave().
+ *
+ * When the node's group is private, force the group content to be private.
+ */
+function commons_groups_node_presave($node) {
+  if (!module_exists('og_access')) {
+    return;
+  }
+
+  $wrapper = entity_metadata_wrapper('node', $node);
+
+  if (og_is_group('node', $node)) {
+    // Determine whether the group is private according to the subscription
+    // field.
+    $private = $wrapper->field_og_subscribe_settings->value() == 'invitation';
+    $wrapper->{OG_ACCESS_FIELD}->set((int)$private);
+    return;
+  }
+
+  if (!og_is_group_content_type('node', $node->type)) {
+    return;
+  }
+
+
+  // Check whether any of the groups are private.
+  $private = FALSE;
+  foreach (array_keys(og_get_group_audience_fields('node', $node->type)) as $field) {
+    if (empty($node->$field)) {
+      continue;
+    }
+
+    foreach ($wrapper->$field as $group_wrapper) {
+      if (empty($group_wrapper->field_og_access_default_value)) {
+        continue;
+      }
+
+      if ($group_wrapper->field_og_access_default_value->value() == TRUE) {
+        // Once a private group was found, there's no need to continue.
+        $private = TRUE;
+        break 2;
+      }
+    }
+  }
+
+  if ($private) {
+    $wrapper->{OG_CONTENT_ACCESS_FIELD}->set(OG_CONTENT_ACCESS_PRIVATE);
+  }
+}
+
+/**
+ * Implements hook_node_update().
+ */
 function commons_groups_node_update($node) {
   $account = user_load($node->uid);
   commons_groups_first_contribution($account, $node);
+
+  if (og_is_group('node', $node)) {
+    commons_groups_set_group_permissions($node);
+  }
 }
 
 /**
-* Implements hook_node_insert().
-*/
+ * Implements hook_node_insert().
+ */
 function commons_groups_node_insert($node) {
   $account = user_load($node->uid);
   commons_groups_first_contribution($account, $node);
+
+  if (og_is_group('node', $node)) {
+    // When creating a new group, this hook happens before OG creates the
+    // group specific roles. Therefore we create the roles here before altering
+    // them in commons_groups_set_group_permissions().
+    og_roles_override('node', $node->type, $node->nid);
+    commons_groups_set_group_permissions($node);
+  }
+}
+
+/**
+ * Set the group's permissions according to field_og_subscribe_settings.
+ *
+ * @param $node
+ *   A group node.
+ */
+function commons_groups_set_group_permissions($node) {
+  // Avoid updating a group subscription twice on the same request.
+  $updated_nodes = &drupal_static(__FUNCTION__);
+  if (!empty($updated_nodes[$node->nid])) {
+    return;
+  }
+  $updated_nodes[$node->nid] = TRUE;
+
+  $wrapper = entity_metadata_wrapper('node', $node);
+  $permission = $wrapper->field_og_subscribe_settings->value();
+  $og_roles = og_roles('node', $node->type, $node->nid);
+  $anon_rid = array_search(OG_ANONYMOUS_ROLE, $og_roles);
+
+  $permissions = array(
+    'subscribe' => $permission == 'approval',
+    'subscribe without approval' => $permission == 'anyone',
+  );
+
+  // Check if the permissions needs to be changed.
+  $changed = FALSE;
+  $old_permissions = og_role_permissions(array($anon_rid => OG_ANONYMOUS_ROLE));
+  foreach ($permissions as $permission => $value) {
+    if (empty($old_permissions[$anon_rid][$permission]) || $old_permissions[$anon_rid][$permission] != $value) {
+      $changed = TRUE;
+    }
+  }
+
+  // Only change the permissions when neccessary.
+  if ($changed) {
+    og_role_change_permissions($anon_rid, $permissions);
+  }
 }
 
 /**
@@ -550,4 +784,25 @@ function commons_groups_preprocess_views_view_grid(&$variables, $hook) {
   if ($variables['view']->name == 'commons_contributors_group' && !empty($variables['title']) && $variables['title'] == 'administrator member') {
     $variables['title'] = t('Organizers');
   }
-}
\ No newline at end of file
+}
+
+/**
+ * Implements hook_field_access().
+ */
+function commons_groups_field_access($op, $field, $entity_type, $entity, $account) {
+  $field_name = $field['field_name'];
+  switch ($field_name) {
+    case 'og_roles_permissions':
+      return FALSE;
+
+    case 'field_og_access_default_value':
+      return $op == 'edit' && module_exists('og_access');
+
+    case 'field_og_subscribe_settings':
+      return $op == 'edit';
+  }
+
+  if (module_exists('og_access') && in_array($field_name, array(OG_CONTENT_ACCESS_FIELD, OG_ACCESS_FIELD))) {
+    return FALSE;
+  }
+}
diff --git a/css/commons_groups.css b/css/commons_groups.css
new file mode 100644
index 0000000..db04154
--- /dev/null
+++ b/css/commons_groups.css
@@ -0,0 +1 @@
+#edit-field-og-access-default-value { margin-left: 20px; }
diff --git a/modules/commons_group_privacy/commons_group_privacy.features.field_base.inc b/modules/commons_group_privacy/commons_group_privacy.features.field_base.inc
deleted file mode 100644
index 99cd47c..0000000
--- a/modules/commons_group_privacy/commons_group_privacy.features.field_base.inc
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-/**
- * @file
- * commons_group_privacy.features.field_base.inc
- */
-
-/**
- * Implements hook_field_default_field_bases().
- */
-function commons_group_privacy_field_default_field_bases() {
-  $field_bases = array();
-
-  // Exported field_base: 'group_access'
-  $field_bases['group_access'] = array(
-    'active' => '1',
-    'cardinality' => '1',
-    'deleted' => '0',
-    'entity_types' => array(),
-    'field_name' => 'group_access',
-    'foreign keys' => array(),
-    'indexes' => array(
-      'value' => array(
-        0 => 'value',
-      ),
-    ),
-    'locked' => '0',
-    'module' => 'list',
-    'no_ui' => TRUE,
-    'settings' => array(
-      'allowed_values' => array(
-        0 => 'Public - accessible to all site users',
-        1 => 'Private - accessible only to group members',
-      ),
-      'allowed_values_function' => '',
-    ),
-    'translatable' => '0',
-    'type' => 'list_boolean',
-  );
-
-  // Exported field_base: 'group_content_access'
-  $field_bases['group_content_access'] = array(
-    'active' => '1',
-    'cardinality' => '1',
-    'deleted' => '0',
-    'entity_types' => array(),
-    'field_name' => 'group_content_access',
-    'foreign keys' => array(),
-    'indexes' => array(
-      'value' => array(
-        0 => 'value',
-      ),
-    ),
-    'locked' => '0',
-    'module' => 'list',
-    'no_ui' => TRUE,
-    'settings' => array(
-      'allowed_values' => array(
-        0 => 'Use group defaults',
-        1 => 'Public - accessible to all site users',
-        2 => 'Private - accessible only to group members',
-      ),
-      'allowed_values_function' => '',
-    ),
-    'translatable' => '0',
-    'type' => 'list_integer',
-  );
-
-  // Exported field_base: 'og_roles_permissions'
-  $field_bases['og_roles_permissions'] = array(
-    'active' => '1',
-    'cardinality' => '1',
-    'deleted' => '0',
-    'entity_types' => array(),
-    'field_name' => 'og_roles_permissions',
-    'foreign keys' => array(),
-    'indexes' => array(
-      'value' => array(
-        0 => 'value',
-      ),
-    ),
-    'locked' => '0',
-    'module' => 'list',
-    'settings' => array(
-      'allowed_values' => array(
-        0 => 'Use default roles and permissions',
-        1 => 'Override default roles and permissions',
-      ),
-      'allowed_values_function' => '',
-    ),
-    'translatable' => '0',
-    'type' => 'list_boolean',
-  );
-
-  return $field_bases;
-}
diff --git a/modules/commons_group_privacy/commons_group_privacy.features.field_instance.inc b/modules/commons_group_privacy/commons_group_privacy.features.field_instance.inc
deleted file mode 100644
index 6ff12af..0000000
--- a/modules/commons_group_privacy/commons_group_privacy.features.field_instance.inc
+++ /dev/null
@@ -1,186 +0,0 @@
-<?php
-/**
- * @file
- * commons_group_privacy.features.field_instance.inc
- */
-
-/**
- * Implements hook_field_default_field_instances().
- */
-function commons_group_privacy_field_default_field_instances() {
-  $field_instances = array();
-   // Get a list of content types that should have the og_groups_ref field added.
-  // Modules can alter this list by implementing hook_strongarm_alter().
-  $commons_groups_entity_types = commons_groups_get_group_content_entity_types();
-  if (!empty($commons_groups_entity_types)) {
-    foreach ($commons_groups_entity_types as $entity_type => $bundles) {
-      foreach(array_keys($bundles) as $bundle) {
-        commons_group_privacy_field_definition($field_instances, $entity_type, $bundle);
-      }
-    }
-  }
-
-  // Exported field_instance: 'node-group-group_access'
-  $field_instances['node-group-group_access'] = array(
-    'bundle' => 'group',
-    'default_value' => array(
-      0 => array(
-        'value' => 0,
-      ),
-    ),
-    'deleted' => '0',
-    'description' => '',
-    'display' => array(
-      'default' => array(
-        'label' => 'above',
-        'module' => 'list',
-        'settings' => array(),
-        'type' => 'list_default',
-        'weight' => 2,
-      ),
-      'teaser' => array(
-        'label' => 'above',
-        'settings' => array(),
-        'type' => 'hidden',
-        'weight' => 0,
-      ),
-    ),
-    'entity_type' => 'node',
-    'field_name' => 'group_access',
-    'label' => 'Group visibility',
-    'required' => TRUE,
-    'settings' => array(
-      'user_register_form' => FALSE,
-    ),
-    'view modes' => array(
-      'full' => array(
-        'label' => 'above',
-        'type' => 'options_onoff',
-      ),
-      'teaser' => array(
-        'label' => 'above',
-        'type' => 'options_onoff',
-      ),
-    ),
-    'widget' => array(
-      'module' => 'options',
-      'settings' => array(),
-      'type' => 'options_buttons',
-      'weight' => 2,
-    ),
-    'widget_type' => 'options_select',
-  );
-
-  // Exported field_instance: 'node-group-og_roles_permissions'
-  $field_instances['node-group-og_roles_permissions'] = array(
-    'bundle' => 'group',
-    'default_value' => array(
-      0 => array(
-        'value' => 0,
-      ),
-    ),
-    'deleted' => '0',
-    'description' => '',
-    'display' => array(
-      'default' => array(
-        'label' => 'above',
-        'module' => 'list',
-        'settings' => array(),
-        'type' => 'list_default',
-        'weight' => 1,
-      ),
-      'teaser' => array(
-        'label' => 'above',
-        'settings' => array(),
-        'type' => 'hidden',
-        'weight' => 0,
-      ),
-    ),
-    'entity_type' => 'node',
-    'field_name' => 'og_roles_permissions',
-    'label' => 'Group roles and permissions',
-    'required' => TRUE,
-    'settings' => array(
-      'user_register_form' => FALSE,
-    ),
-    'view modes' => array(
-      'full' => array(
-        'custom settings' => FALSE,
-        'label' => 'Full',
-        'type' => 'list_default',
-      ),
-      'teaser' => array(
-        'custom settings' => FALSE,
-        'label' => 'Teaser',
-        'type' => 'list_default',
-      ),
-    ),
-    'widget' => array(
-      'module' => 'options',
-      'settings' => array(),
-      'type' => 'options_select',
-      'weight' => 1,
-    ),
-  );
-
-  // Translatables
-  // Included for use with string extractors like potx.
-  t('Group content visibility');
-  t('Group roles and permissions');
-  t('Group visibility');
-
-  return $field_instances;
-}
-
-function commons_group_privacy_field_definition(&$field_instances, $entity_type, $bundle) {
-  // Exported field_instance: 'node-TYPE-group_content_access'
-  $field_instances["$entity_type-$bundle-group_content_access"] = array(
-    'bundle' => $bundle,
-    'default_value' => array(
-      0 => array(
-        'value' => 0,
-      ),
-    ),
-    'deleted' => '0',
-    'description' => '',
-    'display' => array(
-      'default' => array(
-        'label' => 'above',
-        'module' => 'list',
-        'settings' => array(),
-        'type' => 'list_default',
-        'weight' => 5,
-      ),
-      'teaser' => array(
-        'label' => 'above',
-        'settings' => array(),
-        'type' => 'hidden',
-        'weight' => 0,
-      ),
-    ),
-    'entity_type' => $entity_type,
-    'field_name' => 'group_content_access',
-    'label' => 'Group content visibility',
-    'required' => TRUE,
-    'settings' => array(
-      'user_register_form' => FALSE,
-    ),
-    'view modes' => array(
-      'full' => array(
-        'label' => 'above',
-        'type' => 'list_default',
-      ),
-      'teaser' => array(
-        'label' => 'above',
-        'type' => 'list_default',
-      ),
-    ),
-    'widget' => array(
-      'module' => 'options',
-      'settings' => array(),
-      'type' => 'options_select',
-      'weight' => 7,
-    ),
-    'widget_type' => 'options_select',
-  );
-}
diff --git a/modules/commons_group_privacy/commons_group_privacy.info b/modules/commons_group_privacy/commons_group_privacy.info
deleted file mode 100644
index a5714a7..0000000
--- a/modules/commons_group_privacy/commons_group_privacy.info
+++ /dev/null
@@ -1,14 +0,0 @@
-name = Commons Group Privacy
-core = 7.x
-package = Commons - Building blocks
-dependencies[] = commons_groups
-dependencies[] = features
-dependencies[] = list
-dependencies[] = og_access
-features[features_api][] = api:1
-features[field_base][] = group_access
-features[field_base][] = group_content_access
-features[field_base][] = og_roles_permissions
-features[field_instance][] = node-group-group_access
-features[field_instance][] = node-group-og_roles_permissions
-features[field_instance][] = node-post-group_content_access
\ No newline at end of file
diff --git a/modules/commons_group_privacy/commons_group_privacy.install b/modules/commons_group_privacy/commons_group_privacy.install
deleted file mode 100644
index 104f051..0000000
--- a/modules/commons_group_privacy/commons_group_privacy.install
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-/**
-* Revert field instances for group content privacy,
-* which where not added per http://drupal.org/node/1936446.
-*/
-function commons_group_privacy_update_3100() {
-  features_revert(array('commons_group_privacy' => array('field_instance')));
-  return array();
-}
\ No newline at end of file
diff --git a/modules/commons_group_privacy/commons_group_privacy.module b/modules/commons_group_privacy/commons_group_privacy.module
deleted file mode 100644
index 1a431fc..0000000
--- a/modules/commons_group_privacy/commons_group_privacy.module
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * @file
- * Drupal needs this blank file.
- */
-
-
-/**
- * Implements hook_features_pipe_alter().
- *
- */
-function commons_group_privacy_features_pipe_alter(&$pipe, $data, $export) {
-  $group_access_fields = array(
-    'group_content_access', 'og_roles_permissions', 'group_access',
-  );
-  // Prevent Commons Group privacy fields from being piped in features
-  // when a content type includes those fields.
-  if (!empty($pipe['field_instance'])) {
-    foreach ($pipe['field_instance'] as $delta => $value) {
-      $args = explode('-', $value);
-      $field_name = $args[2];
-      if (in_array($field_name, $group_access_fields)) {
-        unset($pipe['field_instance'][$delta]);
-      }
-    }
-  }
-  if (!empty($pipe['field_base'])) {
-    foreach ($pipe['field_base'] as $delta => $value) {
-      if (in_array($delta, $group_access_fields)) {
-        unset($pipe['field_base'][$delta]);
-      }
-    }
-  }
-}
-
-/**
-* Implements hook_system_info_alter().
-*/
-function commons_group_privacy_system_info_alter(&$info, $file, $type) {
-  // Commons Groups dynamically adds the og_group_ref field to
-  // content types that request it by altering the
-  // commons_groups_entity_types variable.
-  // We must add a corresponding line for each field instance
-  // to commons_groups.info so that Features is aware of the instance
-  // and can sucessfully revert the field_instance component back
-  // to its default state.
-  if ($file->name == 'commons_group_privacy') {
-    $group_content_entity_types = commons_groups_get_group_content_entity_types();
-    if (!empty($group_content_entity_types)) {
-      foreach ($group_content_entity_types as $entity_type => $bundles) {
-        foreach(array_keys($bundles) as $bundle) {
-          $info['features']['field_instance'][] = "$entity_type-$bundle-group_content_access";
-        }
-      }
-    }
-  }
-}
\ No newline at end of file
diff --git a/plugins/entityreference/selection/OgCommonsSelectionHandler.class.php b/plugins/entityreference/selection/OgCommonsSelectionHandler.class.php
new file mode 100644
index 0000000..09fcbfd
--- /dev/null
+++ b/plugins/entityreference/selection/OgCommonsSelectionHandler.class.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * OG Commons groups selection handler.
+ */
+
+class OgCommonsSelectionHandler extends OgSelectionHandler {
+
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    return new self($field, $instance, $entity_type, $entity);
+  }
+
+  /**
+   * Overrides OgSelectionHandler::buildEntityFieldQuery().
+   */
+  public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
+    $group_type = $this->field['settings']['target_type'];
+
+    if (empty($this->instance['field_mode']) || $group_type != 'node') {
+      return parent::buildEntityFieldQuery($match, $match_operator);
+    }
+
+    $handler = EntityReference_SelectionHandler_Generic::getInstance($this->field, $this->instance, $this->entity_type, $this->entity);
+    $query = $handler->buildEntityFieldQuery($match, $match_operator);
+
+    // Show only the entities that are active groups.
+    $query->fieldCondition(OG_GROUP_FIELD, 'value', 1);
+    $query->fieldCondition('field_og_subscribe_settings', 'value', 'anyone');
+
+    // Add this property to make sure we will have the {node} table later on in
+    // OgCommonsSelectionHandler::entityFieldQueryAlter().
+    $query->propertyCondition('nid', 0, '>');
+
+    $query->addMetaData('entityreference_selection_handler', $this);
+
+    // FIXME: http://drupal.org/node/1325628
+    unset($query->tags['node_access']);
+
+    $query->addTag('entity_field_access');
+    $query->addTag('og');
+
+    return $query;
+  }
+
+  /**
+   * Overrides OgSelectionHandler::entityFieldQueryAlter().
+   *
+   * Add the user's groups along with the rest of the "public" groups.
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    $gids = og_get_entity_groups();
+    if (empty($gids['node'])) {
+      return;
+    }
+
+    $conditions = &$query->conditions();
+    // Find the condition for the "field_data_field_privacy_settings" query, and
+    // the one for the "node.nid", so we can later db_or() them.
+    $public_condition = array();
+    foreach ($conditions as $key => $condition) {
+      if ($key !== '#conjunction' && is_string($condition['field'])) {
+        if (strpos($condition['field'], 'field_data_field_og_subscribe_settings') === 0) {
+          $public_condition = $condition;
+          unset($conditions[$key]);
+        }
+
+        if ($condition['field'] === 'node.nid') {
+          unset($conditions[$key]);
+        }
+      }
+    }
+
+    if (!$public_condition) {
+      return;
+    }
+
+    $or = db_or();
+    $or->condition($public_condition['field'], $public_condition['value'], $public_condition['operator']);
+    $or->condition('node.nid', $gids['node'], 'IN');
+    $query->condition($or);
+  }
+}
diff --git a/plugins/entityreference/selection/og_commons.inc b/plugins/entityreference/selection/og_commons.inc
new file mode 100644
index 0000000..55fc029
--- /dev/null
+++ b/plugins/entityreference/selection/og_commons.inc
@@ -0,0 +1,6 @@
+<?php
+
+$plugin = array(
+  'title' => t('Commons OG'),
+  'class' => 'OgCommonsSelectionHandler',
+);
