diff --git a/sites/all/modules/taxonomy_access_control/tac.admin.php b/sites/all/modules/taxonomy_access_control/tac.admin.php
index a2c7c2fc0e8b18db8aab362a298e7a32b1961d4b..e997ca99b6e22fcc2d858b75edb66369d46b153a 100644
--- a/sites/all/modules/taxonomy_access_control/tac.admin.php
+++ b/sites/all/modules/taxonomy_access_control/tac.admin.php
@@ -47,10 +47,15 @@ function tac_admin($form, $form_state, $rid = NULL) {
       foreach (taxonomy_get_tree($vocabulary) as $term) {
         $subform['term_' . $term->tid] = array(
           '#title' => $term->name,
-          'view' => array(
-            '#parents'       => array('edit', $rid, $term->tid, 'view'),
+          'list' => array(
+            '#parents'       => array('edit', $rid, $term->tid, 'list'),
             '#type'          => 'checkbox',
-            '#default_value' => (isset($currentValues[$rid][$term->tid]->grant_view) ? $currentValues[$rid][$term->tid]->grant_view : 0),
+            '#default_value' => (isset($currentValues[$rid][$term->tid]->grant_list) ? $currentValues[$rid][$term->tid]->grant_list : 0),
+          ),
+          'create' => array(
+            '#parents'       => array('edit', $rid, $term->tid, 'create'),
+            '#type'          => 'checkbox',
+            '#default_value' => (isset($currentValues[$rid][$term->tid]->grant_create) ? $currentValues[$rid][$term->tid]->grant_create : 0),
           ),
           'update' => array(
             '#parents'       => array('edit', $rid, $term->tid, 'update'),
@@ -79,13 +84,14 @@ function tac_admin($form, $form_state, $rid = NULL) {
 function theme_tac_term_list($variables) {
   $form = $variables['form'];
   
-  $headers = array('Term', 'View', 'Update', 'Delete');
+  $headers = array('Term', 'List', 'Create', 'Update', 'Delete');
   $rows = array();
   foreach (element_children($form) as $key) {
     $rows[] = array(
       'data' => array(
         $form[$key]['#title'],
-        drupal_render($form[$key]['view']),
+        drupal_render($form[$key]['list']),
+        drupal_render($form[$key]['create']),
         drupal_render($form[$key]['update']),
         drupal_render($form[$key]['delete']),
       )
@@ -115,12 +121,12 @@ function tac_admin_submit($form, &$form_state) {
   }
   
 
-  $insert = db_insert('tac_map')->fields(array('rid', 'tid', 'grant_view', 'grant_update', 'grant_delete'));
+  $insert = db_insert('tac_map')->fields(array('rid', 'tid', 'grant_list', 'grant_create', 'grant_update', 'grant_delete'));
   
   foreach ($form_state['values']['edit'] as $rid => $terms) {
     foreach ($terms as $tid => $grants) {
       $insert->values(array(
-        $rid, $tid, $grants['view'], $grants['update'], $grants['delete'],
+        $rid, $tid, $grants['list'], $grants['create'], $grants['update'], $grants['delete'],
       ));
     }
   }
diff --git a/sites/all/modules/taxonomy_access_control/tac.install b/sites/all/modules/taxonomy_access_control/tac.install
index 3aa690423cb24ee38f2e5bcda5916db89dcbb452..e9a503dbdb13bbad538da4448a7a443475228a92 100644
--- a/sites/all/modules/taxonomy_access_control/tac.install
+++ b/sites/all/modules/taxonomy_access_control/tac.install
@@ -45,6 +45,22 @@ function tac_schema()
         'default' => 0,
         'size' => 'tiny',
       ),
+      'grant_create' => array(
+        'description' => 'Boolean indicating whether a user with the realm/grant pair can create this term on a node.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'grant_list' => array(
+        'description' => 'Boolean indicating whether a user with the realm/grant pair can list this term.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
     ),
     'primary key' => array('rid', 'tid'),
     'foreign keys' => array(
@@ -122,6 +138,25 @@ function tac_update_7100()
   db_create_table('tac_map', $table);
 }
 
+function tac_update_7101() {
+  db_add_field('tac_map', 'grant_create', array(
+    'description' => 'Boolean indicating whether a user with the realm/grant pair can create this term on a node.',
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'default' => 0,
+    'size' => 'tiny',
+  ));
+  
+  db_add_field('tac_map', 'grant_list', array(
+    'description' => 'Boolean indicating whether a user with the realm/grant pair can list this term.',
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'default' => 0,
+    'size' => 'tiny',
+  ));
+}
 
 
 
diff --git a/sites/all/modules/taxonomy_access_control/tac.module b/sites/all/modules/taxonomy_access_control/tac.module
index a8f7405032342aba0a92e7d92fcfbb410c065170..a126751d89f529e30b57c0f161fd4048cbde347b 100644
--- a/sites/all/modules/taxonomy_access_control/tac.module
+++ b/sites/all/modules/taxonomy_access_control/tac.module
@@ -40,14 +40,7 @@ function tac_node_access_records($node) {
   $tac_vid = variable_get('tac_vocabulary', -1);
   $fields_to_check = array();
   
-  $fields = field_info_instances('node', $node->type);
-  foreach ($fields as $field) {
-    $fieldInfo = field_info_field($field['field_name']);
-    if ($fieldInfo['type'] != 'taxonomy_term_reference') {
-      continue;
-    }
-    $fields_to_check[] = $field['field_name'];
-  }
+  $fields_to_check = _tac_get_taxonomy_fields_for_node($node);
   
   $selected_tids = array();
   foreach ($fields_to_check as $field) {
@@ -103,3 +96,185 @@ function tac_node_grants($account, $op) {
   
   return $grants;
 }
+
+function tac_form_alter(&$form, &$form_state, $form_id) {
+  if (substr($form_id, -10) == '_node_form') {
+    
+    // If the current user can bypass node access controls, we don't need to filter anything
+    if (user_access('bypass node access')) {
+      return;
+    }
+    
+    $taxonomy_fields = _tac_get_taxonomy_fields_for_node($form['#node']);
+    
+    $query = db_select('tac_map', 'm');
+    $query->fields('m');
+    $query->condition('m.rid', array_keys($GLOBALS['user']->roles), 'IN');
+    $data = $query->execute()->fetchAll();
+    
+    $grants = array();
+    foreach ($data as $row) {
+      if ($row->grant_create) {
+        $grants[$row->tid]['create'] = TRUE;
+      }
+      if ($row->grant_list) {
+        $grants[$row->tid]['list'] = TRUE;
+      }
+    }
+    
+    array_unshift($form['#validate'], 'tac_node_form_validate');
+    foreach ($taxonomy_fields as $field) {
+      
+      // If the terms are displayed as checkboxes, hide/disable them as necessary
+      if ($form[$field]['und']['#type'] == 'checkboxes' || $form[$field]['und']['#type'] == 'radios') {
+        $hidden_checkboxes = 0;
+        foreach ($form[$field]['und']['#options'] as $tid => $term) {
+          if ($tid == '_none') {
+            continue;
+          }
+          if (!isset($grants[$tid]['list']) || !$grants[$tid]['list']) {
+            $form[$field]['und'][$tid]['#type'] = 'hidden';
+            $form_state['storage']['tac'][$field][$tid] = $tid;
+            $hidden_checkboxes++;
+          }
+          if (!isset($grants[$tid]['create']) || !$grants[$tid]['create']) {
+            $form[$field]['und'][$tid]['#disabled'] = 'TRUE';
+            $form_state['storage']['tac'][$field][$tid] = $tid;
+          }
+        }
+        
+        // If all of the checkboxes are hidden, don't display the entire checkboxes elememnt
+        if ($hidden_checkboxes == count($form[$field]['und']['#options'])) {
+          $form[$field]['und']['#prefix'] = '<div style="display: none;">';
+          $form[$field]['und']['#suffix'] = '</div>';
+        }
+      }
+      
+      // If the terms are in a [multi-]select list, hide terms as necessary (since drupal doesn't support disabling)
+      if ($form[$field]['und']['#type'] == 'select') {
+        if ($form[$field]['und']['#multiple']) {
+          unset($form[$field]['und']['#options']['_none']);
+        }
+        foreach ($form[$field]['und']['#options'] as $tid => $term) {
+          if ($tid == '_none') {
+            continue;
+          }
+          if (!isset($grants[$tid]['create']) || !isset($grants[$tid]['list']) || !$grants[$tid]['create'] || !$grants[$tid]['list']) {
+            unset($form[$field]['und']['#options'][$tid]);
+            $form_state['storage']['tac'][$field][$tid] = $tid;
+          }
+        }
+      }
+      
+      if ($form[$field]['und']['#type'] == 'textfield') {
+        form_set_error('tac', "Autocomplete term widgets are not allowed when used with TAC.");
+      }
+    }
+  }
+}
+
+function tac_node_form_validate($form, &$form_state) {
+  if (!isset($form_state['storage']['tac'])) {
+    return;
+  }
+  
+  foreach ($form_state['storage']['tac'] as $field => $locked_terms) {
+    $default_terms = $form[$field]['und']['#default_value'];
+    if ($form[$field]['und']['#type'] == 'select' && !$form[$field]['und']['#multiple']) {
+      $default_terms = $default_terms[0];
+    }
+    
+    $set_terms = array();
+    foreach ($form_state['values'][$field]['und'] as $key => $term_value) {
+      $set_terms[$key] = $term_value['tid'];
+    }
+    
+    // If multiple terms can be selected:
+    if (is_array($default_terms)) {
+      foreach ($locked_terms as $locked_term) {
+        if (in_array($locked_term, $default_terms) && !in_array($locked_term, $set_terms)) {
+          $form_state['values'][$field]['und'][] = array(
+            'tid' => $locked_term,
+          );
+        }
+        if (!in_array($locked_term, $default_terms) && in_array($locked_term, $set_terms)) {
+          form_set_error('tac', 'Attempt to add a denied term detected.');
+          return;
+        }
+      }
+    }
+    // If only one term can be selected:
+    else {
+      if (in_array($default_terms, $locked_terms) && !in_array($default_terms, $set_terms)) {
+        drupal_set_message("A term you don't have access to was alerady selected.", 'warning');
+        $form_state['values'][$field]['und'] = array(array('tid' => $default_terms));
+      }
+    }
+  }
+}
+
+function tac_query_alter(QueryAlterableInterface $query) {
+  if (!$query->hasTag('term_access')) {
+    return;
+  }
+  
+  // We need slightly more advanced filtering on the edit page.  Handle it there.
+  if (arg(2) == 'edit') {
+    return;
+  }
+  
+  // If the current user can bypass node access controls, we don't need to filter anything
+  if (user_access('bypass node access') || user_access('administer taxonomy')) {
+    return;
+  }
+  
+  $alias = '';
+  foreach ($query->getTables() as $table) {
+    if ($table['table'] == 'taxonomy_term_data') {
+      $alias = $table['alias'];
+    }
+  }
+  
+  $query->distinct();
+  $query->addJoin(
+  	'LEFT',
+  	'{tac_map}',
+  	'tm',
+  	"$alias.tid = tm.tid AND tm.rid IN (:rids)",
+    array(':rids' => array_keys($GLOBALS['user']->roles))
+  );
+  $query->where('tm.grant_list = 1 OR tm.grant_list IS NULL');
+}
+
+function _tac_get_taxonomy_fields_for_node($node) {
+  $tac_vid = variable_get('tac_vocabulary', -1);
+  $vocabularies = taxonomy_get_vocabularies();
+  if (!isset($vocabularies[$tac_vid])) {
+    return array();
+  }
+  $vocabulary = $vocabularies[$tac_vid];
+  
+  $taxonomy_fields = array();
+  
+  $fields = field_info_instances('node', $node->type);
+  foreach ($fields as $field) {
+    $fieldInfo = field_info_field($field['field_name']);
+    if ($fieldInfo['type'] != 'taxonomy_term_reference') {
+      continue;
+    }
+    
+    $is_correct_vocabulary = FALSE;
+    foreach ($fieldInfo['settings']['allowed_values'] as $allowed_value) {
+      if ($allowed_value['vocabulary'] == $vocabulary->machine_name) {
+        $is_correct_vocabulary = TRUE;
+      }
+    }
+    if (!$is_correct_vocabulary) {
+      continue;
+    }
+    
+    $taxonomy_fields[] = $field['field_name'];
+  }
+  return $taxonomy_fields;
+}
+