diff --git a/feeds.info b/feeds.info
index eb7387b..6e48db7 100644
--- a/feeds.info
+++ b/feeds.info
@@ -42,6 +42,7 @@ files[] = tests/feeds_mapper.test
 files[] = tests/feeds_mapper_config.test
 files[] = tests/feeds_fetcher_file.test
 files[] = tests/feeds_mapper_format_config.test
+files[] = tests/feeds_mapper_format.test
 files[] = tests/feeds_fetcher_http.test
 files[] = tests/feeds_processor_entity.test
 files[] = tests/feeds_processor_node.test
diff --git a/mappers/text.inc b/mappers/text.inc
index 235aea3..545c845 100644
--- a/mappers/text.inc
+++ b/mappers/text.inc
@@ -40,6 +40,14 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
     if (!empty($instance['settings']['text_processing'])) {
       $targets[$name]['summary_callback'] = 'text_feeds_summary_callback';
       $targets[$name]['form_callback'] = 'text_feeds_form_callback';
+
+      $targets[$name . ':format'] = array(
+        'name' => check_plain($instance['label']) . ': Format',
+        'callback' => 'text_feeds_set_target',
+        'description' => t('The @label field\'s format of the entity. This will overwrite the default or configured format of the field.', array('@label' => $instance['label'])),
+        'summary_callback' => 'text_feeds_format_summary_callback',
+        'form_callback' => 'text_feeds_format_form_callback',
+      );
     }
   }
 }
@@ -50,12 +58,19 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
 function text_feeds_set_target(FeedsSource $source, $entity, $target, array $values, array $mapping = array()) {
   list($field_name, $column) = explode(':', $target . ':value');
 
-  if ($column === 'value' && isset($source->importer->processor->config['input_format'])) {
-    $format = $source->importer->processor->config['input_format'];
-    // Add in default values.
-    $mapping += array(
-      'format' => $format,
-    );
+  if (isset($source->importer->processor->config['input_format'])) {
+    $default_format = $source->importer->processor->config['input_format'];
+
+    if ($column === 'value') {
+      // Add default target configuration for the "value" part of text fields.
+      $mapping += array(
+        'format' => $default_format,
+      );
+    }
+  }
+  if ($column === 'format') {
+    // Add default target configuration for the "format" part of text fields.
+    $mapping += text_feeds_format_defaults($source->importer->processor);
   }
 
   $field = isset($entity->$field_name) ? $entity->$field_name : array('und' => array());
@@ -69,10 +84,25 @@ function text_feeds_set_target(FeedsSource $source, $entity, $target, array $val
     }
 
     if (is_scalar($value) && strlen($value)) {
+      if ($column === 'format') {
+        if (in_array($value, array_filter($mapping['allowed_formats']))) {
+          // Map to format and note that this mapping found place to avoid a
+          // conflict with the target configuration of the 'value' part of the
+          // text field.
+          $field['und'][$delta]['format'] = (string) $value;
+          $entity->feeds_item->format_mapped[$field_name][$delta] = TRUE;
+        }
+      }
+      else {
+        $field['und'][$delta][$column] = (string) $value;
+      }
 
-      $field['und'][$delta][$column] = (string) $value;
-
-      if (isset($mapping['format'])) {
+      // The 'value' part of the text field has target configuration for the
+      // text format, but there is also a target available for mapping to
+      // format directly.
+      // When mapping to format directly, ignore the target configuration.
+      // Else apply the target configuration if set.
+      if (isset($mapping['format']) && empty($entity->feeds_item->format_mapped[$field_name][$delta])) {
         $field['und'][$delta]['format'] = $mapping['format'];
       }
     }
@@ -137,3 +167,93 @@ function text_feeds_form_callback(array $mapping, $target, array $form, array $f
     ),
   );
 }
+
+/**
+ * Summary callback for text format target.
+ *
+ * Displays which text formats from the source will be accepted.
+ *
+ * @see text_feeds_format_form_callback()
+ */
+function text_feeds_format_summary_callback($mapping, $target, $form, $form_state) {
+  global $user;
+  $formats = filter_formats($user);
+
+  $importer = feeds_importer_load($form['#importer']);
+  $mapping += text_feeds_format_defaults($importer->processor);
+
+  $format_names = array();
+  foreach (array_filter($mapping['allowed_formats']) as $format) {
+    $format_names[] = $formats[$format]->name;
+  }
+
+  return t('Allowed formats: %formats', array('%formats' => implode(', ', $format_names)));
+}
+
+/**
+ * Form callback for text format target.
+ *
+ * Allows to restrict the text formats to accept from the source.
+ *
+ * @see text_feeds_format_summary_callback()
+ */
+function text_feeds_format_form_callback($mapping, $target, $form, $form_state) {
+  global $user;
+  $formats_options = array();
+  $formats = filter_formats($user);
+  foreach ($formats as $id => $format) {
+    $formats_options[$id] = $format->name;
+  }
+
+  // Processor-wide input format setting.
+  $importer = feeds_importer_load($form['#importer']);
+  $mapping += text_feeds_format_defaults($importer->processor);
+
+  $config['allowed_formats'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Allowed text formats'),
+    '#options' => $formats_options,
+    '#default_value' => $mapping['allowed_formats'],
+    '#required' => TRUE,
+    '#description' => t('Select the text formats to accept from the feed.<br />Any other format will be ignored and the default will be used.')
+  );
+
+  return $config;
+}
+
+/**
+ * Returns default configuration for the text format mapper.
+ *
+ * @param FeedsProcessor $processor
+ *   The processor that is used for processing the items during import.
+ *   The processor holds configuration for the importer's default text format,
+ *   which is one of the text formats that should be allowed by default for the
+ *   text format target.
+ *
+ * @return array
+ *   The default configuration for the text format mapper.
+ */
+function text_feeds_format_defaults(FeedsProcessor $processor) {
+  $default_processor_format = isset($processor->config['input_format']) ? $processor->config['input_format'] : filter_fallback_format();
+  $default_site_format = filter_fallback_format();
+
+  if ($default_processor_format == $default_site_format) {
+    // If the site's text format is the same as processor's text format only one
+    // text format is allowed by default.
+    return array(
+      'allowed_formats' => array(
+        $default_processor_format,
+      ),
+    );
+  }
+  else {
+    // If the site's text format is different from the processor's text format
+    // both text formats are allowed by default.
+    return array(
+      'allowed_formats' => array(
+        $default_site_format,
+        $default_processor_format,
+      ),
+    );
+  }
+}
diff --git a/tests/feeds.test b/tests/feeds.test
index b3ce145..e803525 100644
--- a/tests/feeds.test
+++ b/tests/feeds.test
@@ -468,7 +468,14 @@ class FeedsWebTestCase extends DrupalWebTestCase {
         // Set some settings.
         $edit = array();
         foreach ($config as $key => $value) {
-          $edit["config[$i][settings][$key]"] = $value;
+          if (is_array($value)) {
+            foreach ($value as $subkey => $subvalue) {
+              $edit["config[$i][settings][$key][$subkey]"] = $subvalue;
+            }
+          }
+          else {
+            $edit["config[$i][settings][$key]"] = $value;
+          }
         }
         $this->drupalPostAJAX(NULL, $edit, 'mapping_settings_update_' . $i);
         $this->drupalPost(NULL, array(), t('Save'));
diff --git a/tests/feeds/nodes_text_format.csv b/tests/feeds/nodes_text_format.csv
new file mode 100644
index 0000000..89de894
--- /dev/null
+++ b/tests/feeds/nodes_text_format.csv
@@ -0,0 +1,4 @@
+"guid","title","body","body_format","alpha","alpha_format"
+1,"Lorem ipsum","Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.","allowed_text_format","Lorem","non_allowed_text_format"
+2,"Ut wisi enim ad minim veniam","Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.","non_allowed_text_format","Ut wisi","allowed_text_format"
+3,"Duis autem vel eum iriure dolor","Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.","plain_text"
diff --git a/tests/feeds_mapper_format.test b/tests/feeds_mapper_format.test
new file mode 100644
index 0000000..a038044
--- /dev/null
+++ b/tests/feeds_mapper_format.test
@@ -0,0 +1,347 @@
+<?php
+
+/**
+ * @file
+ * Contains FeedsMapperFormatTestCase.
+ */
+
+/**
+ * Class for testing mapping to text format.
+ */
+class FeedsMapperFormatTestCase extends FeedsMapperTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Mapper: Text format',
+      'description' => 'Test mapping to text format for text fields.',
+      'group' => 'Feeds',
+    );
+  }
+
+  /**
+   * Basic test for mapping to text format.
+   *
+   * This test does the following:
+   * 1. It ensures that mapping to text format works as intended.
+   * 2. It ensures that mapping to text format has precedence on the target
+   *    configuration of text fields itself, which also can touch the text
+   *    format of text fields. To ensure this, there is mapped to two format
+   *    targets, as well as to two text field targets. For the first text field
+   *    the format target is defined first, while for the second text field the
+   *    text field itself comes first. This way we've taken care of that the
+   *    order of mappings doesn't matter.
+   * 3. It ensures that not every format specified in the source is accepted.
+   *    This is done to avoid security issues. Imagine someone would specify
+   *    "php" as the format to use in the source. If that format can not be
+   *    blocked, then someone could (unintentionally) import executable php
+   *    code.
+   */
+  public function test() {
+    // Create a content type.
+    $typename = $this->createContentType(array(), array(
+      'alpha' => array(
+        'type' => 'text',
+        'instance_settings' => array(
+          'instance[settings][text_processing]' => 1,
+        ),
+      ),
+    ));
+
+    // Create two filter formats. One that may be used and one that may NOT be
+    // used.
+    $edit = array(
+      'format' => 'allowed_text_format',
+      'name' => 'Allowed text format',
+      // Authenticated users.
+      'roles[2]' => TRUE,
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
+    $edit = array(
+      'format' => 'non_allowed_text_format',
+      'name' =>  'Non-allowed text format',
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
+
+    // Create and configure importer.
+    $this->createImporterConfiguration();
+    $this->setPlugin('syndication', 'FeedsFileFetcher');
+    $this->setPlugin('syndication', 'FeedsCSVParser');
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('bundle' => $typename));
+    // We map to two format targets here, to ensure that the order of mappings
+    // does not matter.
+    $this->addMappings('syndication', array(
+      0 => array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      1 => array(
+        'source' => 'body_format',
+        'target' => 'body:format',
+        'allowed_formats' => array(
+          'allowed_text_format' => 'allowed_text_format',
+        ),
+      ),
+      2 => array(
+        'source' => 'body',
+        'target' => 'body',
+      ),
+      3 => array(
+        'source' => 'alpha',
+        'target' => 'field_alpha',
+      ),
+      4 => array(
+        'source' => 'alpha_format',
+        'target' => 'field_alpha:format',
+        'allowed_formats' => array(
+          'allowed_text_format' => 'allowed_text_format',
+        ),
+      ),
+    ));
+
+    // Import csv file.
+    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/nodes_text_format.csv');
+    $this->assertText('Created 3 nodes');
+
+    // Assert that the body and alpha fields of the nodes got the expected text
+    // format. Note that of the first node, the body field uses an allowed
+    // format, but the alpha field does not. For the second node it is the exact
+    // opposite.
+    $node = node_load(1);
+    $this->assertEqual('allowed_text_format', $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 1 got the expected format.');
+    $this->assertEqual(filter_fallback_format(), $node->field_alpha[LANGUAGE_NONE][0]['format'], 'The alpha field of node 1 got the expected format.');
+    $node = node_load(2);
+    $this->assertEqual(filter_fallback_format(), $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 2 got the expected format.');
+    $this->assertEqual('allowed_text_format', $node->field_alpha[LANGUAGE_NONE][0]['format'], 'The alpha field of node 2 got the expected format.');
+  }
+
+  /**
+   * Tests if only the default text formats are accepted when format mapper is
+   * not configured.
+   *
+   * Testing is done as such:
+   * 1. First, three nodes are created that have a text format other than the
+   *    default.
+   * 2. An importer is created that has its default format is set to
+   *    'allowed_text_format'.
+   *    Mapping against body format is done, but without any configuration.
+   * 3. Importing is done.
+   * 4. Asserted is that the three updated nodes have the expected formats:
+   *    - Node 1 should have 'allowed_text_format', since that one is allowed
+   *      because of the importer's default setting.
+   *    - The format of node 2 should be unchanged, because the source specified
+   *      a now-allowed format.
+   *    - Node 3 should have 'plain_text', because that is the site default text
+   *      format.
+   */
+  public function testDefaults() {
+    // Create a content type.
+    $typename = $this->createContentType();
+
+    // Create a filter format to use for the three nodes to create.
+    $format_init = drupal_strtolower($this->randomName());
+    $edit = array(
+      'format' => $format_init,
+      'name' => $this->randomName(),
+      // Authenticated users.
+      'roles[2]' => TRUE,
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
+
+    // Create three nodes to update. Set the text format of the body field.
+    // The titles are taken from nodes_text_format.csv.
+    // Note that $nodes variable is used at the end of this test to assert that
+    // the body values did not change as there is not being mapped to body.
+    $nodes = array(
+      array(
+        'title' => 'Lorem ipsum',
+        'body' => self::randomString(),
+      ),
+      array(
+        'title' => 'Ut wisi enim ad minim veniam',
+        'body' => self::randomString(),
+      ),
+      array(
+        'title' => 'Duis autem vel eum iriure dolor',
+        'body' => self::randomString(),
+      ),
+    );
+    foreach ($nodes as $node_data) {
+      $this->drupalCreateNode(array(
+        'type' => $typename,
+        'title' => $node_data['title'],
+        'body' => array(
+          LANGUAGE_NONE => array(
+            array(
+              'value' => $node_data['body'],
+              'format' => $format_init,
+            ),
+          ),
+        ),
+      ));
+    }
+
+    // Assert that the created nodes have the expected format assigned.
+    $node = node_load(1, NULL, TRUE);
+    $this->assertEqual($format_init, $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 1 got the expected format.');
+    $node = node_load(2, NULL, TRUE);
+    $this->assertEqual($format_init, $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 2 got the expected format.');
+    $node = node_load(3, NULL, TRUE);
+    $this->assertEqual($format_init, $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 3 got the expected format.');
+
+    // Create a filter format to use as default for the importer.
+    $edit = array(
+      'format' => 'allowed_text_format',
+      'name' => 'Allowed text format',
+      // Authenticated users.
+      'roles[2]' => TRUE,
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
+
+    // Create and configure importer.
+    $this->createImporterConfiguration();
+    $this->setPlugin('syndication', 'FeedsFileFetcher');
+    $this->setPlugin('syndication', 'FeedsCSVParser');
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array(
+      'bundle' => $typename,
+      'input_format' => 'allowed_text_format',
+      'update_existing' => 2,
+    ));
+    $this->addMappings('syndication', array(
+      0 => array(
+        'source' => 'title',
+        'target' => 'title',
+        'unique' => 1,
+      ),
+      1 => array(
+        'source' => 'body_format',
+        'target' => 'body:format',
+      ),
+    ));
+
+    // Import csv file.
+    $this->importFile('syndication', $this->absolutePath() . '/tests/feeds/nodes_text_format.csv');
+    $this->assertText('Updated 3 nodes');
+
+    // Assert that only the text format of nodes 1 and 3 had changed. Also
+    // assert that the body field did not change.
+    $node = node_load(1, NULL, TRUE);
+    $this->assertEqual('allowed_text_format', $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 1 got the expected format.');
+    $this->assertEqual($nodes[0]['body'], $node->body[LANGUAGE_NONE][0]['value'], 'The value of the body field of node 1 did not change.');
+    $node = node_load(2, NULL, TRUE);
+    $this->assertEqual($format_init, $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 2 got the expected format.');
+    $this->assertEqual($nodes[1]['body'], $node->body[LANGUAGE_NONE][0]['value'], 'The value of the body field of node 2 did not change.');
+    $node = node_load(3, NULL, TRUE);
+    $this->assertEqual('plain_text', $node->body[LANGUAGE_NONE][0]['format'], 'The body field of node 3 got the expected format.');
+    $this->assertEqual($nodes[2]['body'], $node->body[LANGUAGE_NONE][0]['value'], 'The value of the body field of node 3 did not change.');
+  }
+
+  /**
+   * Tests the filter formats an user has access to.
+   *
+   * An user that has no permission to use some of the text formats on the
+   * website, should not be able to choose these as an allowed format to accept
+   * from the source.
+   */
+  public function testWithLimitedPrivileges() {
+    // Create content type with a field that uses a text format.
+    $typename = $this->createContentType(array(), array(
+      'alpha' => array(
+        'type' => 'text',
+        'instance_settings' => array(
+          'instance[settings][text_processing]' => 1,
+        ),
+      ),
+    ));
+
+    // Create a new user with limited privileges.
+    $account = $this->drupalCreateUser(array('administer feeds'));
+
+    // Create filter format the user may use.
+    $format1 = drupal_strtolower($this->randomName());
+    $edit1 = array(
+      'format' => $format1,
+      'name' => $this->randomName(),
+      // Authenticated users.
+      'roles[2]' => TRUE,
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit1, t('Save configuration'));
+
+    // Create filter format the user may NOT use.
+    $rid = $this->drupalCreateRole(array());
+    $format2 = drupal_strtolower($this->randomName());
+    $edit2 = array(
+      'format' => $format2,
+      'name' => $this->randomName(),
+      'roles[' . $rid . ']' => TRUE,
+    );
+    $this->drupalPost('admin/config/content/formats/add', $edit2, t('Save configuration'));
+
+    // Login as the user that may only use certain formats.
+    $this->drupalLogin($account);
+
+    // Create importer and ensure the user can use the first format.
+    $this->createImporterConfiguration();
+    $this->setPlugin('syndication', 'FeedsFileFetcher');
+    $this->setPlugin('syndication', 'FeedsCSVParser');
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('bundle' => $typename));
+    $this->addMappings('syndication', array(
+      0 => array(
+        'source' => 'alpha_format',
+        'target' => 'field_alpha:format',
+        'allowed_formats' => array($format1 => $format1),
+      ),
+    ));
+
+    // Check user can choose first, but not second format as an option.
+    $this->drupalPostAJAX(NULL, array(), 'mapping_settings_edit_0');
+    $this->assertFieldByName('config[0][settings][allowed_formats][' . $format1 . ']', NULL, format_string('Text format %format can be chosen.', array('%format' => $format1)));
+    $this->assertNoFieldByName('config[0][settings][allowed_formats][' . $format2 . ']', NULL, format_string('Text format %format can NOT be chosen.', array('%format' => $format2)));
+  }
+
+  /**
+   * Tests if format mapper is only available for fields that have filtered text
+   * enabled.
+   *
+   * Only text fields that are configured to be filtered text have use for a
+   * text format. Other text fields can only be plain text. In this test it is
+   * ensured that there is no format target for text fields that can only be
+   * plain text.
+   */
+  public function testMapperAvailability() {
+    // Create content type with three fields. Two that support text formats
+    // and one that doesn't.
+    $typename = $this->createContentType(array(), array(
+      'alpha' => array(
+        'type' => 'text',
+        'instance_settings' => array(
+          'instance[settings][text_processing]' => 1,
+        ),
+      ),
+      'beta' => array(
+        'type' => 'text_long',
+        'instance_settings' => array(
+          'instance[settings][text_processing]' => 1,
+        ),
+      ),
+      'gamma' => array(
+        'type' => 'text',
+        'instance_settings' => array(
+          'instance[settings][text_processing]' => 0,
+        ),
+      ),
+    ));
+
+    // Create importer.
+    $this->createImporterConfiguration();
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('bundle' => $typename));
+
+    // Get mapping targets from importer.
+    $importer = feeds_importer('syndication');
+    $targets = $importer->processor->getMappingTargets();
+
+    // Assert availability of format mapper.
+    $this->assertTrue(isset($targets['field_alpha:format']), 'A format mapper for the alpha field exists.');
+    $this->assertTrue(isset($targets['field_beta:format']), 'A format mapper for the beta field exists.');
+    $this->assertFalse(isset($targets['field_gamma:format']), 'A format mapper for the gamma field does not exists.');
+  }
+
+}
